#include "gl_util.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"

namespace webrtc {
namespace {
  constexpr const char *TAG = "GLUtil";
}

void GlUtil::CheckNoGLES2Error(const std::string &msg) {
  GLenum error = glGetError();
  if (error != GL_NO_ERROR) {
    RTC_LOG(LS_ERROR) << TAG <<", msg:" << msg << ", CheckNoGLES2Error: " << error;
    RTC_CHECK(false) << msg << ", CheckNoGLES2Error: " << error;
  }
}

GLuint GlUtil::GenerateTexture(GLenum target) {
  GLuint texture_id;
  glGenTextures(1, &texture_id);
  glBindTexture(target, texture_id);
  glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  CheckNoGLES2Error("GenerateTexture");
  return texture_id;
}

std::unique_ptr<float[]> GlUtil::CreateFloatBuffer(const float *coords, size_t size) {
  auto buffer = std::make_unique<float[]>(size);
  std::memcpy(buffer.get(), coords, size * sizeof(float));
  return buffer;
}

void GlUtil::DeleteTexture(GLuint texture_id) {
  glDeleteTextures(1, &texture_id);
}

bool GlUtil::IsOesTexture(int gl_target) {
  return gl_target == GL_TEXTURE_EXTERNAL_OES;
}

void GlUtil::ConvertToGLMatrix(const Matrix &matrix, GLfloat *matrix4x4) {
  std::array<float, 9> values;
  matrix.GetValues(values);

  // The 2d Matrix looks like this:
  // [x1 y1 w1]
  // [x2 y2 w2]
  // [x3 y3 w3]
  // We want to contruct a matrix that looks like this:
  // [x1 y1  0 w1]
  // [x2 y2  0 w2]
  // [ 0  0  1  0]
  // [x3 y3  0 w3]
  // Since it is stored in column-major order, it looks like this:
  // [x1 x2 0 x3
  //  y1 y2 0 y3
  //   0  0 1  0
  //  w1 w2 0 w3]
  // clang-format off
  matrix4x4[0] = values[0]; // MSCALE_X
  matrix4x4[1] = values[3]; // MSKEW_Y
  matrix4x4[2] = 0.0f;
  matrix4x4[3] = 0.0f;

  matrix4x4[4] = values[1]; // MSKEW_X
  matrix4x4[5] = values[4]; // MSCALE_Y
  matrix4x4[6] = 0.0f;
  matrix4x4[7] = 0.0f;

  matrix4x4[8]  = 0.0f;
  matrix4x4[9]  = 0.0f;
  matrix4x4[10] = 1.0f; // 固定值用于Z轴
  matrix4x4[11] = 0.0f;

  matrix4x4[12] = values[2]; // MTRANS_X
  matrix4x4[13] = values[5]; // MTRANS_Y
  matrix4x4[14] = 0.0f;
  matrix4x4[15] = values[8]; // MPERSP_2
}
}